﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace GLinq
{
    public class Element<T>
    {
        public T Content { get { throw new NotImplementedException(); } }
        public int GetIndex(int dimension)
        {
            // this method should not be actually executed.
            throw new NotImplementedException();
        }
    }

    public abstract class ElementIndex
    {
    }

    public class ElementIndex1D : ElementIndex
    {
        public int X { get; set; }
        public ElementIndex1D(int x)
        {
            this.X = x;
        }
    }

    public class ElementIndex2D : ElementIndex
    {
        public int X { get; set; }
        public int Y { get; set; }

        public ElementIndex2D(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }
    }

    public class ElementIndex3D : ElementIndex
    {
        public int X { get; set; }
        public int Y { get; set; }
        public int Z { get; set; }
        public ElementIndex3D(int x, int y, int z)
        {
            this.X = x;
            this.Y = y;
            this.Z = z;
        }
    }

    public class ElementIndexCollector
    {
        public void AddIndex1D(int x)
        {
            throw new NotImplementedException();
        }
        public void AddIndex2D(int x, int y)
        {
            throw new NotImplementedException();
        }
        public void AddIndex3D(int x, int y, int z)
        {
            throw new NotImplementedException();
        }
    }

    public static class GridOperatorExtension
    {
        public static Grid<TOut> Select<T, TOut>(this Grid<T> input, Expression<Func<Element<T>, TOut>> selector)
        {
            return new Grid<TOut>(new SelectExpression(input.Expression, selector));
        }

        public static Grid<TOut> SelectParallel<T, TOut>(this Grid<T> input, Expression<Func<Element<T>, TOut>> selector)
        {
            return new Grid<TOut>(new SelectParallelExpression(input.Expression, selector));
        }

        public static Buffer<TOut> Select<T, TOut>(this Buffer<T> input, Expression<Func<Element<T>, TOut>> selector)
        {
            return new Buffer<TOut>(new SelectExpression(input.Expression, selector));
        }

        public static Buffer<TOut> SelectParallel<T, TOut>(this Buffer<T> input, Expression<Func<Element<T>, TOut>> selector)
        {
            return new Buffer<TOut>(new SelectParallelExpression(input.Expression, selector));
        }

        public static Grid<T> Union<T>(this Grid<Grid<T>> input)
            where T:Mergeable
        {
            return new Grid<T>(new UnionExpression(input.Expression));
        }


        public static Grid<Buffer<T>> Scatter<T>(this Buffer<T> input, Expression<Func<Element<T>, IEnumerable<ElementIndex>>> destSelector)
        {
            return new Grid<Buffer<T>>(new ScatterExpression(input.Expression, destSelector));
        }

        public static Grid<Buffer<T>> ScatterMany<T>(this Grid<Buffer<T>> input, Expression<Func<Element<T>, IEnumerable<ElementIndex>>> destSelector)
        {
            return new Grid<Buffer<T>>(new ScatterManyExpression(input.Expression, destSelector));
        }

        public static Buffer<T> StreamOut<T>(this Grid<Buffer<T>> input)
        {
            return new Buffer<T>(new StreamOutExpression(input.Expression));
        }

        public static Buffer<T> Where<T>(this Buffer<T> input, Expression<Func<Element<T>, bool>> filter)
        {
            return new Buffer<T>(new WhereExpression(input.Expression, filter));
        }

        public static TOut Consume<T, TOut>(this ConsumableQueue<T> input, int maxLength, Expression<Func<Buffer<T>, TOut>> work)
        {
            throw new NotImplementedException();
        }

        public static ConsumedBuffer<T> ConsumeOnce<T>(this ConsumableQueue<T> input, int maxLength)
        {
            throw new NotImplementedException();
        }

        public static int Sum<T>(this Grid<T> input, Expression<Func<T, int>> selector)
        {
            throw new NotImplementedException();
        }

        public static T Min<T>(this Grid<T> input, Expression<Func<T, int>> keySelector)
        {
            throw new NotImplementedException();
        }

        public static T First<T>(this Buffer<T> buffer)
        {
            throw new NotImplementedException();
        }

        public static T First<T>(this ConsumableQueue<T> buffer)
        {
            throw new NotImplementedException();
        }
    }
}
